﻿SmitearWebGL.Objects.Ocean.OceanManager = Class.extend(
{
	init : function()
	{
		this._registClass( "SmitearWebGL.Objects.Ocean.OceanManager" );
		
		this._pIndexBuffer = null;
		this._pBaseBuffer = null;
		this._pAnimBuffer = new Array( SmitearWebGL.Objects.Ocean.OceanManager.k_total_water_meshes );
		this._pRenderMethod = null;
		
		this._fWindX = 0;
		this._fWindY = 0;
		this._fWindSpeed = 0;
		this._fWaveHeight = 0;
		this._fDirectionalDependence = 0;
		this._fSuppressSmallWavesFactor = 0;
		this._fLargestPossibleWave = 0;
		this._fSuppressSmallWaves = 0;
		
		this._activeBuffer = 0;
		this._tickCounter = 0;
		this._fInterpolation = 0;
		this._fTime = 0;
		
		this._colH0 = new Array( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_freq_area );
		this._colH = new Array( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_area );
		this._colN = new Array( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_area );
		this._colAngularFreq = new Array( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_area );
		
		this._pAnimBuffer[0] = 0;
		this._pAnimBuffer[1] = 0;
		
		for ( var i = 0; i < this._colH0.length; ++ i )
			this._colH0[i] = new SmitearWebGL.Objects.Ocean.OceanManager.sComplex();
		
		for ( i = 0; i < this._colH.length; ++ i )
		{
			this._colH0[i] = new SmitearWebGL.Objects.Ocean.OceanManager.sComplex();
			this._colN[i] = new SmitearWebGL.Objects.Ocean.OceanManager.sComplex();
			this._colAngularFreq[i] = 0.0;
		}
	}
	,
	indexBuffer : function()
	{
		return this._pIndexBuffer;
	}
	,
	renderMethod : function()
	{
		return this._pRenderMethod;
	}
	,
	getOceanHeight : function( x, y )
	{
	    return -this._colH[this.getOffsetWrap(x, y)].real;
	}
	,
	getOceanNormalX : function( x, y )
	{
	    return this._colN[this.getOffsetWrap(x, y)].real;
	}
	,
	getOceanNormalY : function( x, y )
	{
	    return this._colN[this.getOffsetWrap(x, y)].imag;
	}
	,
	getKx : function( x )
	{
	    return SmitearWebGL.Core.Math.TWO_PI * x;
	}
	,
	getKy : function( y )
	{
	    return SmitearWebGL.Core.Math.TWO_PI * y;
	}
	,
	getAngularFrequency : function( fKLength )
	{
	    // special version for deep water
	    return( Math.sqrt( SmitearWebGL.Core.Math.GRAVITY_CONSTANT * fKLength ) );
	
		// Note: If we wanted to take the water depth into account, we could
		// use the slower equation:
		// Math.sqrt( SmitearWebGL.Core.Math.GRAVITY_CONSTANT * fKLength * tanhf( fKLength * depth ) )
	}
	,
	getIndexH0 : function( x, y )
	{
	    return ( x + SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size+ ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size + 1 ) *
	    		( y + SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size) );
	}
	,
	getIndex : function( x, y )
	{
	    return ( x + ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size ) + SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size *
	    		( y + SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size) );
	}
	,
	getIndexFFT : function( x, y )
	{
	    // get the appropriate index to store data in the right order for the 2d fft
	    // (that is, dc is stored at (0, 0) and not at ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size, SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size ) !!!)
	    return( ( x & ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size - 1 ) ) + SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size * ( y & ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size - 1 ) ) );
	}
	,
	getOffset : function( x, y )
	{
	    return x + SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size * y;
	}
	,
	getOffsetWrap : function( x, y )
	{
	    return( this.getOffset( x & ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size - 1 ),
	    		y & ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size - 1 ) ) );
	}
	,
	create : function()
	{
		this.setOceanParameters( 4357,
								SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultWindDirection,
								SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultWindSpeed,
								SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultWaveHeight,
								SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultDirectionalDependence,
								SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultSuppressSmallWavesFactor );
		
		//create vbo
		this._pBaseBuffer = g_vertexBufferManager.createResource( "__cOceanManager_base_buffer__" );
		this._pBaseBuffer.createElementDescription( 2, 0, 0, SmitearWebGL.Resources.Buffer.DataType.FLOAT, SmitearWebGL.Resources.Buffer.AttribLocation.POSITION0 );
		
		var i = 0;
		var u = 0.0;
		var v = 0.0;
		var uvStep = 1.0 / ( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size - 1 );
		
		var pVertices = this._pBaseBuffer.lock( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size *
												SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size );

		for ( var y = 0; y < SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size; ++ y )
		{
			for ( var x = 0; x < SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size; ++ x )
			{
				pVertices[i++] = u*ocean_tile_size;
				pVertices[i++] = v*ocean_tile_size;

				u += uvStep;
			}
			v += uvStep;
			u = 0.0;
		}
		
		this._pBaseBuffer.unlock();
		
		//create ibo
		this._pIndexBuffer = g_indexBufferManager.createResource( "__cOceanManager_index_buffer__" );
		this._pIndexBuffer.createSingleStripGrid( SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size,
												SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size,
												1,1, SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size, 0 );

		//
		// prepare for the first frame
		//
		this._fTime = 1.0;
		this.animateHeightTable();
		this.animateNormalTable();
		this.horizontalFFT(this._colH );
		this.horizontalFFT(this._colN );
		this.verticalFFT(this._colH );
		this.verticalFFT(this._colN );
		this._tickCounter = 0;

		// build the dynamic vertex buffers
		for ( i = 0; i < k_total_water_meshes; ++ i )
		{
			var name = "__cOceanManager_buffer_" + i + "__";
			this._pAnimBuffer[i] = g_vertexBufferManager.createResource( name );

			this._pAnimBuffer[i].create(
			k_grid_area,
			sizeof(sAnimVertex),
			FLAG(cIndexBuffer::nDynamicOverwriteBit),
			0);
			this.fillVertexBuffer(this._pAnimBuffer[i]);
		}
	}
	,
	phillipsSpectrum : function( fKx, fKy )
	{
		// normalize the 2D vector defined by (fKx, fKy)
	    var fKLength = Math.sqrt( fKx * fKx + fKy * fKy );
		fKLength = Math.max(fKLength, 1e-8);
	    var fScale( 1.0 / fKLength );
	    fKx *= fScale;
	    fKy *= fScale;
	
		// perform the phillipsSpectrum calculation
	    return ( this._fWaveHeight * 
	             expf( -1.0 / Square( fKLength * this._fLargestPossibleWave ) - Square( fKLength * this._fSuppressSmallWaves ) ) * 
	             powf( fKx * this._fWindX + fKy * this._fWindY, this._fDirectionalDependence ) / powf( fKLength, 4.0 ) );
	}
	,
	setOceanParameters : function( ulSeed, fWindDirection, fWindSpeed, fWaveHeight, fDirectionalDependence, fSuppressSmallWavesFactor )
	{
		this._fWindX                    = Math.cos( fWindDirection );
		this._fWindY                    = Math.sin( fWindDirection );
		this._fWindSpeed                = fWindSpeed;
		this._fWaveHeight               = fWaveHeight;
		this._fDirectionalDependence    = fDirectionalDependence;
		this._fSuppressSmallWavesFactor = fSuppressSmallWavesFactor;

		this._fLargestPossibleWave =  this._fWindSpeed * this._fWindSpeed / SmitearWebGL.Core.Math.GRAVITY_CONSTANT;
		this._fSuppressSmallWaves  = this._fLargestPossibleWave * this._fSuppressSmallWavesFactor;

		// init H0
		for( var j = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;j<= SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; ++j )
		{
			for( var i = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;i<= SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; ++i )
			{
				sComplex cmpRnd;
				SmitearWebGL.Core.Math.gaussRandomPair(cmpRnd.real, cmpRnd.imag);

				var scalar = SmitearWebGL.Core.Math. * Math.sqrt( this.phillipsSpectrum(this.getKx(i), this.getKy(j)));

				cmpRnd.real *= scalar;
				cmpRnd.imag *= scalar;

				this._colH0[ this.getIndexH0(i,j) ] = cmpRnd;
			}
		}

		// init angular frequencies
		for(var j= -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;j< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; ++j )
		{
			for( var i = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;i< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; ++i )
			{
				var fKLength( Math.sqrt( this.getKx(i) * this.getKx(i) + this.getKy(j) * this.getKy(j) ) );
				this._colAngularFreq[this.getIndex(i,j)] = this.getAngularFrequency(fKLength);
			}
		}
	}
	,
	FFT : function( pCmpTable )
	{
	    var nn,i,i1,j,k,i2,l,l1,l2;
	    var c1,c2,treal,timag,t1,t2,u1,u2,z;
	    
	    nn = SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size;
	    
		var pCmpi;
		var pCmpj;
		var pCmpi1;
	
		// bit reversal
	    i2 = nn >> 1;
	    j= 0;
	    for(i= 0;i< nn - 1; ++i )
	    {
	        if(i<j)
	        {
				pCmpi = pCmpTable[i];
				pCmpj = pCmpTable[j];
	
	            treal = pCmpi.real;
	            timag = pCmpi.imag;
	            pCmpi.real = pCmpj.real;
	            pCmpi.imag = pCmpj.imag;
	            pCmpj.real = treal;
	            pCmpj.imag = timag;
	        }
	
	        k = i2;
	        while( k <=j)
	        {
	           j-= k;
	            k >>= 1;
	        }
	
	       j+= k;
	    }
	    
	    // Compute the FFT
	    c1 = -1.0;
	    c2 = 0.0;
	    l2 = 1;
	    for( l = 0; l < k_log_grid_size; ++l )
	    {
	        l1 = l2;
	        l2 <<= 1;
	        u1 = 1.0;
	        u2 = 0.0;
	        for(j= 0;j< l1; ++j )
	        {
	            for(i= j;i< nn;i+= l2 )
	            {
	                i1 =i+ l1;
	
					pCmpi = &pCmpTable[i];
					pCmpi1 = &pCmpTable[i1];
	
	                t1 = u1 * pCmpi1.real- u2 * pCmpi1.imag;
	                t2 = u1 * pCmpi1.imag+ u2 * pCmpi1.real;
	                pCmpi1.real = pCmpi.real - t1;
	                pCmpi1.imag = pCmpi.imag - t2;
	                pCmpi.real += t1;
	                pCmpi.imag += t2;
	            }
	
	            z =  u1 * c1 - u2 * c2;
	            u2 = u1 * c2 + u2 * c1;
	            u1 = z;
	        }
	
	        c2 = fast_sqrt( ( 1.0 - c1 ) * 0.5 );
	        c1 = fast_sqrt( ( 1.0 + c1 ) * 0.5 );
	    }
	}
	,
	horizontalFFT : function( pCmpTable )
	{
	    // Transform the rows
		for( var j = 0;j< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size; ++j )
	    {
			FFT(&pCmpTable[SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size*j]);
	    }
	}
	,
	verticalFFT : function( pCmpTable )
	{
	    sComplex tableCopy[ SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size ];
	
	    // Transform the columns
	    for( var i = 0;i< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size; ++i )
	    {
	        for( var j = 0;j< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size; ++j )
	        {
	            tableCopy[j] = pCmpTable[ this.getOffset(i,j) ];
	        }
	        
	        FFT(tableCopy);
	        
	        for(var j= 0;j< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size; ++j )
	        {
	            pCmpTable[ this.getOffset(i,j) ] = tableCopy[j];
	        }
	    }
	}
	,
	update : function()
	{
		$THROW( this._tickCounter >= k_animateHeight, "invalid tick counter" );
		$THROW( this._tickCounter < k_total_process_stages, "invalid tick counter" );
	
		switch(this._tickCounter)
		{
			case k_animateHeight:
				this._fTime = 
					applicationTimer.elapsedTime()*0.15f;
				this.animateHeightTable();
				break;
			case k_animateNormal:
				this.animateNormalTable();
				break;
			case k_heightFFTv:
				this.verticalFFT(this._colH );    
				break;
			case k_heightFFTh:
				this.horizontalFFT(this._colH );    
				break;
			case k_normalFFTv:
				this.verticalFFT(this._colN );    
				break;
			case k_normalFFTh:
				this.horizontalFFT(this._colN );    
				break;
			case k_uploadBuffer:
				this.fillVertexBuffer(
					this._pAnimBuffer[this._activeBuffer]);
				break;
			default:
				++this._activeBuffer;
				if (this._activeBuffer 
					>= k_total_water_meshes)
				{
					this._activeBuffer = 0;
				}
				break;
		};
	
		// compute the interpolation factor for
		// the vertices currently in use
		this._fInterpolation = //0.0;
			(var)(this._tickCounter+1)
			/(var)(k_total_process_stages);
	
		++this._tickCounter;
		if (this._tickCounter == k_total_process_stages)
		{
			this._tickCounter = k_animateHeight;
			this._fInterpolation = 0.0;
		}
	}
	,
	animateHeightTable : function()
	{
		for(var j = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;
			j< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; 
			++j )
	    {
	        for(var i = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;
				i< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; 
				++i )
	        {
	            var fAngularFreq=
					this._colAngularFreq[ this.getIndex(i,j)] 
					* this._fTime;
	            var fCos=FastCos(fAngularFreq);
	            var fSin=FastSine(fAngularFreq);
	
				var indexFFT = this.getIndexFFT(i,j);
				var indexHO = this.getIndexH0(i,j);
				var indexHOn = this.getIndexH0(-i,-j);
	
	            // this.update the tale of complex numbers 
				// affecting water surface height.
	            this._colH[indexFFT].real= 
					( this._colH0[indexHO].real
						+ this._colH0[indexHOn].real ) * fCos -
	                ( this._colH0[indexHO].imag 
						+ this._colH0[indexHOn].imag ) * fSin;
	
	            this._colH[indexFFT].imag= 
					( this._colH0[indexHO].real
						- this._colH0[indexHOn].real ) * fSin + 
	                ( this._colH0[indexHO].imag 
						- this._colH0[indexHOn].imag ) * fCos;
			}
		}
	}
	,
	animateNormalTable : function()
	{
		for( var j = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;j< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; ++j )
	    {
	        for( var i = -SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size;i< SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_half_grid_size; ++i )
	        {
	            // this.update normal
	            var fKx( this.getKx(i) );
	            var fKy( this.getKy(j) );
	
	            // Put the two functions for n(Kx) and n(Ky) into one complex array
	            // (that is, multiply the n(Ky) by i and add it to n(Kx) ) to do one FFT instead of two.
	            // This assumes that the inverse of both transforms are real functions (as it is the case here)!
	            // After the FFT the x component of the normal will be stored in the real part, the y component 
	            // in the complex part of this._colN respectively.
	            this._colN[ this.getIndexFFT(i,j) ].real= 
					-this._colH[ this.getIndexFFT(i,j) ].imag * fKx - this._colH[ this.getIndexFFT(i,j) ].real * fKy;
	            this._colN[ this.getIndexFFT(i,j) ].imag=  
					this._colH[ this.getIndexFFT(i,j) ].real * fKx - this._colH[ this.getIndexFFT(i,j) ].imag * fKy;
			}
		}
	}
	,
	fillVertexBuffer : function( pVertexBuffer )
	{
		var pStartVertex = pVertexBuffer.lock( k_grid_area );
		var pVertices = pStartVertex;
		var k_grid_size = SmitearWebGL.Objects.Ocean.OceanManager.eConstants.k_grid_size;
		var i = 0;
		
		for ( var y = 0; y < k_grid_size; ++ y )
		{
			for ( var x = 0; x < k_grid_size; ++ x )
			{
				//map to zPos
				pVertices[i ++] = this.getOceanHeight( x, y ) * ocean_tile_height;
				
				//map to normal
				pVertices[i ++] = this.getOceanNormalX( x, y );
				pVertices[i ++] = this.getOceanNormalY( x, y );
			}       
		}

		// make sure all edge data is the same
		var pLeftVert		= pStartVertex[0];
		var pTopVert		= pStartVertex[0];
		var pRightVert		= pStartVertex[3 * k_grid_size - 1];
		var pBottomVert		= pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size];
		var pEndVert		= pStartVertex[3 * ( ( k_grid_size * k_grid_size ) - 1)];
		
		//map to pLeftVert
		pStartVertex[0] = pStartVertex[3 * k_grid_size - 1 + 0];
		pStartVertex[1] = pStartVertex[3 * k_grid_size - 1 + 1];
		pStartVertex[2] = pStartVertex[3 * k_grid_size - 1 + 2];
		
		//map to pBottomVert
		pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size + 0] = pStartVertex[3 * k_grid_size - 1 + 0];
		pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size + 1] = pStartVertex[3 * k_grid_size - 1 + 1];
		pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size + 2] = pStartVertex[3 * k_grid_size - 1 + 2];
		
		//map to pEndVert
		pStartVertex[3 * ( ( k_grid_size * k_grid_size ) - 1) + 0] = pStartVertex[3 * k_grid_size - 1 + 0];
		pStartVertex[3 * ( ( k_grid_size * k_grid_size ) - 1) + 1] = pStartVertex[3 * k_grid_size - 1 + 1];
		pStartVertex[3 * ( ( k_grid_size * k_grid_size ) - 1) + 2] = pStartVertex[3 * k_grid_size - 1 + 2];

		for ( i = 0; i < k_grid_size; ++ i )
		{
			//map to pLeftVert
			pStartVertex[0] = pStartVertex[3 * k_grid_size - 1 + 0];
			pStartVertex[1] = pStartVertex[3 * k_grid_size - 1 + 1];
			pStartVertex[2] = pStartVertex[3 * k_grid_size - 1 + 2];
			
			//map to pTopVert
			pStartVertex[0] = pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size + 0];
			pStartVertex[1] = pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size + 1];
			pStartVertex[2] = pStartVertex[3 * ( k_grid_size - 1 ) * k_grid_size + 2];

			pTopVert++;
			pBottomVert++;
			pLeftVert += k_grid_size;
			pRightVert += k_grid_size;
		}

		pVertexBuffer.unlock();
	}
	,
	setRenderMethod : function( pMethod )
	{
		safe_release(this._pRenderMethod);
		this._pRenderMethod = pMethod;
	
		if (this._pRenderMethod)
		{
			this._pRenderMethod.AddRef();
		}
	}
	,
	render : function()
	{
		const cCamera* pCamera = TheGameHost.activeCamera();
	
		static cVector4 uvOffset(
			1.0,
			3.0f,
			0.0,
			0.0);
		uvOffset.z += 0.01f;
		uvOffset.w += 0.01f;
	
		// determine how many ocean tiles to draw to fill the camera view
		cRect3d world = pCamera.searchRect();
		
		// align the world rect to our ocean tile grid
		world.rect2d /= ocean_tile_size;
		var x0 = realToInt32_floor(world.x0);
		var x1 = realToInt32_ceiling(world.x1);
		var y0 = realToInt32_floor(world.y0);
		var y1 = realToInt32_ceiling(world.y1);
	
		if (this._pRenderMethod)
		{
			cEffectFile* pEffectFile = 
				this._pRenderMethod.getActiveEffect();
			cSurfaceMaterial* pSurfaceMaterial = 
				this._pRenderMethod.getActiveMaterial();
	
			if (pEffectFile)
			{
				// unlike regular objects, we do not render through the render
				// queue. Instead, we render on-demand using our internal settings
				if (pEffectFile.begin())
				{
					LPDIRECT3DDEVICE9 d3dDevice = 
						TheGameHost.d3dDevice();
	
					// supply our matrix to the render method
					pEffectFile.setMatrix(
						cEffectFile::k_worldViewProjMatrix, 
						&pCamera.viewProjMatrix());
	
					// supply our material to the render method
					pEffectFile.applySurfaceMaterial(
						pSurfaceMaterial);
	
					// activate the geometry buffers
					this._pIndexBuffer.activate();
					this._pBaseBuffer.activate(0, 0, true);
					
					var primary_buffer = this._activeBuffer -2;
					var secondary_buffer = this._activeBuffer -1;
	
					if (primary_buffer <0) primary_buffer += k_total_water_meshes;
					if (secondary_buffer <0) secondary_buffer += k_total_water_meshes;
	
					this._pAnimBuffer[primary_buffer].activate(1, 0, false);
					this._pAnimBuffer[secondary_buffer].activate(2, 0, false);
	
					pEffectFile.setParameter(
						cEffectFile::k_uvScaleOffset,
						&uvOffset);
	
					var totalPasses = pEffectFile.totalPasses();
					for (var i=0; i<totalPasses; ++i)
					{
						pEffectFile.activatePass(i);
	
						for (var y=y0; y<y1; ++y)
						{
							for (var x=x0; x<x1; ++x)
							{
								cVector4 scaleOffset(
									this._fInterpolation,
									1.0/8000.0f,
									x * ocean_tile_size,
									y * ocean_tile_size);
	
								pEffectFile.setParameter(
									cEffectFile::k_posScaleOffset,
									&scaleOffset);
								
								pEffectFile.CommitChanges();
								HRESULT hr = d3dDevice.DrawIndexedPrimitive(
									this._pIndexBuffer.primitiveType(),
									0,
									0,
									k_grid_area,
									0,
									this._pIndexBuffer.primitiveCount());
	
							}
						}
						pEffectFile.endPass();
					}
					pEffectFile.end();
				}
			}
		}
	}
}
);

SmitearWebGL.Objects.Ocean.OceanManager.sComplex =
{
	real : 0,
	imag : 0,
	equal : function( rsh )
	{
		this.real = rsh.real;
		this.imag = rsh.imag;
		
		return this;
	}
}

SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultWindDirection = Math.PI * 0.5;
SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultWindSpeed = 32.0;
SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultWaveHeight = 384.0;
SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultDirectionalDependence = 4.0;
SmitearWebGL.Objects.Ocean.OceanManager.s_fDefaultSuppressSmallWavesFactor = 0.00005;

SmitearWebGL.Objects.Ocean.OceanManager.k_total_water_meshes = 3;

SmitearWebGL.Objects.Ocean.OceanManager.eConstants =
{
	k_grid_size :			64,
	k_half_grid_size :		32,
	k_log_grid_size :		6,
	k_grid_area :			64 * 64,
	k_freq_area :			65 * 65
}